package manage.commons.utils;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * 验证码工具类
 * 
 * @author dongji
 * @since 2012-11-9 下午05:35:35
 */
public class RandomCode {
	/** 加密的key **/
	private static final String encryptKey = "$^rm#5crm321-=-123mrc5#mr^$";
	/** 图片的宽度 **/
	private int width = 102;
	/** 图片的高度 **/
	private int height = 28;
	/** 验证码中字符的数量 **/
	private int codeCount = 4;
	/** 验证码图片 **/
	private BufferedImage buffImg;
	/** 验证码字符串 **/
	private String randomCode;
	private Random random = new Random();

	public RandomCode() {
		this.createRandomImage();
	}

	/**
	 * 加密验证码(写入cookie中的值)
	 * 
	 * @param randomCode
	 * @return
	 */
	public static String getEncryptValue(String randomCode) {
		if (StringUtils.isBlank(randomCode)) {
			randomCode = " ";
		}
		randomCode = randomCode.toLowerCase();
		return DigestUtils.md5Hex(randomCode + encryptKey + randomCode);
	}

	/**
	 * 获取当前验证码的加密字符串
	 * 
	 * @return
	 */
	public String getEncryptValue() {
		return getEncryptValue(this.getCheckCodeStr());
	}

	/**
	 * 
	 * 获取验证码本身
	 * 
	 * @return randomCode
	 */
	public RandomCode createRandomImage() {
		setCheckCodeStr(randomCode());
		setBuffImg(disturb());
		return this;
	}

	/**
	 * 随机产生的验证码
	 * 
	 * @return String
	 */
	private String randomCode() {
		StringBuffer randomCode = new StringBuffer(codeCount);
		String strRand = null;
		int xx = width / (codeCount + 1);
		int codeY = height - 4;
		char[] codeSequence = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j',
				'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
				'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J',
				'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
				'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
		Graphics2D graphics = graphicsInit();
		graphics.setColor(createColor());
		for (int i = 0; i < codeCount; i++) {
			strRand = String.valueOf(codeSequence[random
					.nextInt(codeSequence.length)]);
			randomCode.append(strRand);
			graphics.drawString(strRand, (i + 1) * xx, codeY);
		}
		return randomCode.toString();
	}

	private Color createColor() {
		Color color[] = new Color[10];
		for (int i = 0; i < 10; i++) {
			color[i] = getRandColor(0, 255);
		}
		return color[random.nextInt(10)];
	}

	public Color getRandColor(int fc, int bc) {
		if (fc > 255)
			fc = 255;
		if (bc > 255)
			bc = 255;
		Random rand = new Random();
		int r = fc + rand.nextInt(bc - fc);
		int g = fc + rand.nextInt(bc - fc);
		int b = fc + rand.nextInt(bc - fc);
		return new Color(r, g, b);
	}

	private Graphics2D graphicsInit() {
		Graphics2D graphics = buffImgInit().createGraphics();
		// 设置背景颜色
		graphics.setColor(getRandColor(230, 238));
		graphics.fillRect(0, 0, width, height);
		graphics.setFont(new Font("Comic Sans MS", Font.PLAIN, 18));
		graphics.drawRect(0, 0, width - 1, height - 1);
		return graphics;
	}

	private BufferedImage buffImgInit() {
		buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		return buffImg;
	}

	private BufferedImage disturb() {
		drawDisturbLine(buffImg.createGraphics());
		return twistImage();
	}

	private void drawDisturbLine(Graphics2D graphics) {
		graphics.setColor(getRandColor(160, 250));
		int x = 0;
		int y = 0;
		int xl = 0;
		int yl = 0;
		for (int i = 0; i < 15; i++) {
			x = random.nextInt(width);
			y = random.nextInt(height);
			xl = random.nextInt(20);
			yl = random.nextInt(10);
			graphics.drawLine(x, y, x + xl, y + yl);
		}
	}

	private BufferedImage twistImage() {
		double dMultValue = random.nextInt(7) + 3;// 波形的幅度倍数，越大扭曲的程序越高，一般为3
		double dPhase = random.nextInt(6);// 波形的起始相位，取值区间（0-2＊PI）
		BufferedImage destBi = new BufferedImage(buffImg.getWidth(),
				buffImg.getHeight(), BufferedImage.TYPE_INT_RGB);
		for (int i = 0; i < destBi.getWidth(); i++) {
			for (int j = 0; j < destBi.getHeight(); j++) {
				int nOldX = getXPosition4Twist(dPhase, dMultValue,
						destBi.getHeight(), i, j);
				int nOldY = j;
				if (nOldX >= 0 && nOldX < destBi.getWidth() && nOldY >= 0
						&& nOldY < destBi.getHeight()) {
					destBi.setRGB(nOldX, nOldY, buffImg.getRGB(i, j));
				}
			}
		}
		return destBi;
	}

	private int getXPosition4Twist(double dPhase, double dMultValue,
			int height, int xPosition, int yPosition) {
		double PI = 3.1415926535897932384626433832799; // 此值越大，扭曲程度越大
		double dx = (double) (PI * yPosition) / height + dPhase;
		double dy = Math.sin(dx);
		return xPosition + (int) (dy * dMultValue);
	}

	public BufferedImage getBuffImg() {
		return buffImg;
	}

	public void setBuffImg(BufferedImage buffImg) {
		this.buffImg = buffImg;
	}

	public String getCheckCodeStr() {
		return randomCode;
	}

	public void setCheckCodeStr(String checkCodeStr) {
		this.randomCode = checkCodeStr;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getCodeCount() {
		return codeCount;
	}

	public void setCodeCount(int codeCount) {
		this.codeCount = codeCount;
	}

}